import json
from datetime import datetime
from decimal import Decimal

from django.http import JsonResponse, HttpResponseBadRequest
from django.utils import timezone
from django.views import View

# 订单结算视图
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.viewmixin import LoginMixin


class OrderSettlementView(LoginMixin, View):
    def get(self, request):
        # - 1获取用户信息user
        user = request.user
        # - 2获取当前用户的所有收货地址
        adds = Address.objects.filter(is_deleted=False, user=user)
        # 2.1转成字典
        addresses_list = []
        for address in adds:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })

        print(addresses_list)

        # - 3获取购物车里选中的商品信息
        # 3.1连接redis
        redis_conn = get_redis_connection('carts')
        # - 3.2获取hash {sku_id:count}
        carts_dict = redis_conn.hgetall("cart_%s" % user.id)
        #  - 3.3获取set
        selected_list = redis_conn.smembers('selected_%s' % user.id)

        new_cart_dict = {}
        # 遍历所有选中的id列表
        for sku_id in selected_list:
            # 　把数据存到新的字典new_cart_dict　　并且转为int
            count = carts_dict[sku_id]
            new_cart_dict[int(sku_id)] = int(count)

        try:
            # new_cart_dict 是所有选中的商品的id和数量 并且是转为int后的
            skus = SKU.objects.filter(id__in=new_cart_dict.keys())
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400,
                                 'errmsg': '数据查询失败'})

        # - 3.4重新组织字典数据
        sku_list = []
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': new_cart_dict[sku.id],
                'price': sku.price
            })

        # Decimal保存小数  需要非常精准的时候 使用
        freight = Decimal('10.00')

        # - 4返回响应
        context = {
            'addresses': addresses_list,
            'skus': sku_list,
            'freight': freight,
        }
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'context': context})


"""
提交订单  生成订单和订单里的商品
路由  post  /orders/commit/

后端
接受两个参数  address_id  pay_method
商品数据可以在redis里自己查 价格自己计算
步骤
1  获取用户对象user 和address_id  pay_method
2  校验数据
3  把数据保存到数据库
    1 保存订单数据 order_info
    生成订单号
    总数量计算  临时 赋值0
    总金额计算  临时 赋值0
    根据pay_method来悬着一个订单状态status

    2 保存订单的商品数据 order_goods
    连接redis
    获取hash
    获取set
    遍历选中的商品  构成一个新的字典 并且转为int
    根据id去数据库查询商品信息
    判断库存是否够  count:3   stock(库存):1   count<=stock
    如果库存够 stock-=count    销量 sales+=count


    计算订单 总数量计算 和 总金额计算

    把redis里购物车选中的商品信息移除

4返回响应
"""


class OrderCommitView(LoginMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 1获取用户对象user 和address_id pay_method
        user = request.user
        json_data = json.loads(request.body)
        address_id = json_data.get("address_id")
        pay_method = json_data.get("pay_method")
        # 2 校验数据
        # 校验参数
        if not all([address_id, pay_method]):
            return HttpResponseBadRequest('缺少必传参数')
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return HttpResponseBadRequest('参数address_id错误')
        # 判断pay_method是否合法
        if pay_method not in {OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']}:
            return HttpResponseBadRequest('参数pay_method错误')

        # 3 把数据保存到数据库
        # 3.1
        # 保存订单数据 order_info
        # 生成订单号 年月日时分秒+用户编号  %f微秒    %09d表示显示为9位 左侧不够补0
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)
        # order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)
        # 总数量计算 临时 赋值0
        total_count = 0
        # 总金额计算 临时 赋值0
        total_amount = 0
        freight = Decimal('10.00')
        # 根据pay_method来悬着一个订单状态status
        # 如果是支付宝 那么状态就是待付款 否则是待发货
        status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else \
            OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        from django.db import transaction
        with transaction.atomic():  # 开启事务
            # 创建 回滚的点
            save_id = transaction.savepoint()
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address_id=address_id,
                    total_count=total_count,
                    total_amount=total_amount,
                    freight=freight,
                    pay_method=pay_method,
                    status=status,
                )
                print(order)
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('订单保存失败')
            #
            # 3.2 保存订单的商品数据 order_goods
            # 连接redis
            redis_conn = get_redis_connection('carts')
            # 获取hash {sku_id:count}
            carts_dict = redis_conn.hgetall("cart_%s" % user.id)
            # 获取set
            selected_list = redis_conn.smembers('selected_%s' % user.id)

            new_cart_dict = {}
            # 遍历所有选中的id列表
            for sku_id in selected_list:
                # 　把数据存到新的字典new_cart_dict　　并且转为int
                count = carts_dict[sku_id]
                new_cart_dict[int(sku_id)] = int(count)

            try:
                # new_cart_dict 是所有选中的商品的id和数量 并且是转为int后的
                skus = SKU.objects.filter(id__in=new_cart_dict.keys())
            except Exception as e:
                # 回滚到保存点
                transaction.savepoint_rollback(save_id)
                print(e)
                return JsonResponse({'code': 400,
                                     'errmsg': '数据查询失败'})

            try:
                # 遍历skus 生成每个sku的订单商品数据 order_goods对象
                for sku in skus:

                    while True:
                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        print("读取库存")

                        # 判断库存是否够 count: 3 stock(库存): 1 count <= stock
                        count = new_cart_dict[sku.id]
                        print(sku.id, sku.stock)
                        if count > sku.stock:
                            # 回滚到保存点
                            print("库存不足回滚")
                            transaction.savepoint_rollback(save_id)

                            return JsonResponse({'code': 400,
                                                 'errmsg': '库存不足'})
                        # 如果库存够 stock -= count 销量 sales += count
                        # import time
                        # time.sleep(5)

                        # sku.stock -= count
                        # sku.sales += count
                        # sku.save()
                        new_stock = origin_stock - count  # 新的库存
                        new_sales = origin_sales + count  # 新的销量
                        # result 是更新到的数据的条数
                        result = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock,
                                                                                          sales=new_sales)
                        if result == 0:
                            continue

                        OrderGoods.objects.create(
                            order_id=order_id,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )

                        # 计算订单 总数量计算 和 金额计算
                        # 把单个商品的数量 累加到订单的总数量里
                        order.total_count += count
                        # 把单个商品的总价 累加到订单的总价里
                        order.total_amount += count * sku.price
                        break

                # 总价 加上运费
                order.total_amount += order.freight
                # 保存对象
                order.save()
                print("保存 成功")
            except Exception as e:
                print(e)
                # 回滚到保存点
                transaction.savepoint_rollback(save_id)
                return HttpResponseBadRequest('订单保存失败')

            # 提交从保存点到当前状态的所有数据库事务操作
            transaction.savepoint_commit(save_id)

        # 把redis里购物车选中的商品信息移除
        redis_conn.hdel('cart_%s' % user.id, *selected_list)
        redis_conn.srem('selected_%s' % user.id, *selected_list)
        # 4 返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})
